# -*- coding: utf-8 -*-
# Gestión de área de impresión de la aplicación.

## vipera, un diseñador de aplicaciones para Python
##     Copyright (C) 2011 Ángel Luis García García
##
##    This program is free software: you can redistribute it and/or modify
##    it under the terms of the GNU General Public License as published by
##    the Free Software Foundation, either version 3 of the License, or
##    (at your option) any later version.
##
##    This program is distributed in the hope that it will be useful,
##    but WITHOUT ANY WARRANTY; without even the implied warranty of
##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##    GNU General Public License for more details.
##
##    You should have received a copy of the GNU General Public License
##    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import wx
import wx.lib.agw.hyperlink as enlace_web

import codecs
import os

from impresion_vista import dialogo_impresion
from python_to_html_vipera import py_to_html
from i18n_vipera import t

class dialogo_impresion_p(dialogo_impresion):
    '''Diálogo de área de impresión'''
    def __init__(self, parent, frame_principal, print_data, fich_imp, fich_html, idioma = None):
        '''Constructor de clase'''
        dialogo_impresion.__init__(self, parent)
        # Idioma.
        self.l = idioma
        # Cambiamos idioma de clases en wxFB.
        self.SetTitle(t(u'Área de impresión', self.l))
        self.m_radioBtn_diagrama.SetLabel(t(u'Diagrama uml de módulo', self.l))
        self.m_radioBtn_codigo.SetLabel(t(u'Código Python generado', self.l))
        self.m_checkBox_codigo_html.SetLabel(t(u'Exportar a HTML', self.l))
        self.m_radioBtn_diagrama_ing_inv.SetLabel(t(u'Diagrama uml', self.l))
        self.m_checkBox_editor.SetLabel(t(u'Exportar a HTML', self.l))
        self.m_button_conf.SetLabel(t(u'Configurar', self.l))
        self.m_button_imprimir.SetLabel(t(u'Imprimir', self.l))        
        # Recogemos datos...
        self.__fich_imp = fich_imp
        self.__fich_html = fich_html 
        self.print_data = print_data
        # Referencia al frame principal.
        self.__padre = frame_principal
        # Referencia del editor de ingeniería inversa.
        self.__editor_ing_inv = frame_principal.ing_inversa.panel_editor.panel.editor
        # Referencia al editor que muestra el código Python generado.
        self.__codigo = frame_principal.panel.panel_editor.get_editor()
        # Referencia al ogl de ingeniería inversa.
        self.__ogl_ing_inv = frame_principal.ing_inversa.panel_designer.panel.panel
        # OGL's de módulos.
        self.__modulos = frame_principal.panel.lista_modulos
        
    def __pasar_a_html(self, editor):
        '''Parseo de código Python para pasarlo a HTML'''
        # Creamos fichero temporal con el código del editor.
        f = codecs.open(self.__fich_imp,'w','utf-8')
        f.write(editor.GetText())
        f.close()
        # Creamos fichero html con código Python.
        html = py_to_html(self.__fich_imp, self.__fich_html, idioma = self.l)
        html.cargar_fichero()
        ret, msj = html.crear_fichero_html()
        if not ret:
            wx.MessageBox(msj, t(u"Atención", self.l), wx.OK)
            return
        # Lanzamos la pagina web en el navegador por defecto.
        lanzadera_web = enlace_web.HyperLinkCtrl(self, -1)
        lanzadera_web.Show(False)
        lanzadera_web.GotoURL(os.path.realpath(self.__fich_html), True, False)    
        # Nos limpiamos el objeto lanzadera.
        lanzadera_web.Destroy()
    
    def OnImprimir(self, event):
        '''Impresión según opciones elegidas'''
        # Ing. inversa - Editor.
        if self.m_radioBtn_editor.GetValue():
            # HTML
            if self.m_checkBox_editor.GetValue():
                self.__pasar_a_html(self.__editor_ing_inv)
            else:
                # Solo texto.
                f_imprimir_texto(self.__editor_ing_inv, self.__padre, self.print_data, self.l)
        # Código Python del generador.
        if self.m_radioBtn_codigo.GetValue():
            # HTML
            if self.m_checkBox_codigo_html.GetValue():
                self.__pasar_a_html(self.__codigo)
            else:
                # Solo texto.
                f_imprimir_texto(self.__codigo, self.__padre, self.print_data, self.l)
        # Diagrame UML ing. inversa.
        if self.m_radioBtn_diagrama_ing_inv.GetValue():
            f_imprimir_ogl(self.__ogl_ing_inv, self.__padre, self.print_data, self.l)
        # Diagrama UML del diseñador de clases en módulos.
        if self.m_radioBtn_diagrama.GetValue():
            # Obtenemos la referencia del ogl.
            ogl = self.__padre.panel.panel_ogl.panel
            # Llamamos a la función de impresión.
            self.__padre.PrintData = f_imprimir_ogl(ogl, self.__padre, self.print_data, self.l)

    def OnConfImp(self, event):
        '''Configuración de impresión'''
        self.print_data = f_configurar_impresion(self.print_data, self.__padre)
        
class MyPrintout(wx.Printout):
    '''Clase que hereda de wx.Printout para impresión de canvas'''
    
    def __init__(self, canvas):
        '''Constructor de clase'''
        wx.Printout.__init__(self)
        self.canvas = canvas

    def HasPage(self, page):
        '''HasPage'''
        return True

    def GetPageInfo(self):
        '''GetPageInfo'''
        return (1, 1, 1, 1)

    def OnPrintPage(self, page):
        '''OnPrintPage'''
        dc = self.GetDC()
        # One possible method of setting scaling factors...
        maxX = self.canvas.GetSize()[0]
        maxY = self.canvas.GetSize()[1]
        # Let's have at least 50 device units margin
        marginX = 50
        marginY = 50
        # Add the margin to the graphic size
        maxX = maxX + (2 * marginX)
        maxY = maxY + (2 * marginY)
        # Get the size of the DC in pixels
        (w, h) = dc.GetSizeTuple()
        # Calculate a suitable scaling factor
        scaleX = float(w) / maxX
        scaleY = float(h) / maxY
        # Use x or y scaling factor, whichever fits on the DC
        actualScale = min(scaleX, scaleY)
        # Calculate the position on the DC for centering the graphic
        posX = (w - (self.canvas.GetSize()[0] * actualScale)) / 2.0
        posY = (h - (self.canvas.GetSize()[1] * actualScale)) / 2.0
        # Set the scale and origin
        dc.SetUserScale(actualScale, actualScale)
        dc.SetDeviceOrigin(int(posX), int(posY))
        self.canvas.Redraw(dc)
        # dc.DrawText("Página: %d" % page, marginX/2, maxY-marginY)
        return True

class EditorPrintout(wx.Printout):
    '''Clase que hereda de wx.Printout para imprimir texto por impresora.'''
    def __init__(self, text, title, margins):
        '''Constructor de clase'''
        # Llamamos al constructor de wx.Printout.
        wx.Printout.__init__(self, title)
        # Obtenemos una lista con las líneas del texto.
        self.lines = text.split('\n')
        # Y los márgenes...
        self.margins = margins

    def HasPage(self, page):
        '''HasPage'''
        # ¿Cuántas páginas?
        return page <= self.numPages

    def GetPageInfo(self):
        '''GetPageInfo'''
        return (1, self.numPages, 1, self.numPages)

    def CalculateScale(self, dc):
        '''CalculateScale'''
        # Se escala el DC al tamaño de la pantalla.
        ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
        ppiScreenX, ppiScreenY = self.GetPPIScreen()
        logScale = float(ppiPrinterX)/float(ppiScreenX)
        # Ajustamos la escala.
        pw, ph = self.GetPageSizePixels()
        dw, dh = dc.GetSize()
        scale = logScale * float(dw)/float(pw)
        dc.SetUserScale(scale, scale)
        self.logUnitsMM = float(ppiPrinterX)/(logScale*25.4)

    def CalculateLayout(self, dc):
        '''CalculateLayout'''
        # Determinamos márgenes.
        topLeft, bottomRight = self.margins
        dw, dh = dc.GetSize()
        self.x1 = topLeft.x * self.logUnitsMM
        self.y1 = topLeft.y * self.logUnitsMM
        self.x2 = dc.DeviceToLogicalXRel(dw) - bottomRight.x * self.logUnitsMM
        self.y2 = dc.DeviceToLogicalYRel(dh) - bottomRight.y * self.logUnitsMM
        # Ponemos un buffer en la página. 
        self.pageHeight = self.y2 - self.y1 - 2*self.logUnitsMM
        font = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
        dc.SetFont(font)
        self.lineHeight = dc.GetCharHeight()
        self.linesPerPage = int(self.pageHeight/self.lineHeight)

    def OnPreparePrinting(self):
        '''OnPreparePrinting'''
        # Calculamos el número de páginas. 
        dc = self.GetDC()
        self.CalculateScale(dc)
        self.CalculateLayout(dc)
        self.numPages = len(self.lines) / self.linesPerPage
        if len(self.lines) % self.linesPerPage != 0: self.numPages += 1

    def OnPrintPage(self, page):
        '''OnPrintPage'''
        # Imprimimos una página.
        dc = self.GetDC()
        self.CalculateScale(dc)
        self.CalculateLayout(dc)
        # Dibujamos el contorno de página.
        dc.SetPen(wx.Pen("black", 0))
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
        r = wx.RectPP((self.x1, self.y1), (self.x2, self.y2))
        dc.DrawRectangleRect(r)
        dc.SetClippingRect(r)
        # Se dibuja las líneas de texto para esta página.
        line = (page-1) * self.linesPerPage
        x = self.x1 + self.logUnitsMM
        y = self.y1 + self.logUnitsMM
        while line < (page * self.linesPerPage):
            dc.DrawText(self.lines[line], x, y)
            y += self.lineHeight
            line += 1
            if line >= len(self.lines): break
        return True

def f_imprimir_texto(editor, frame, print_data, idioma = None):
    '''Función para imprimir texto del editor'''
    pdata = print_data
    margenes = (wx.Point(15,15), wx.Point(15,15))
    # Inicializamos vista preliminar de impresión.
    data = wx.PrintDialogData(pdata)
    # Obtenemos texto del editor.
    text = editor.GetText()
    # Instanciamos clase Printout.
    printout1 = EditorPrintout(text, t(u"Título", idioma), margenes)
    printout2 = EditorPrintout(text, t(u"Título", idioma), margenes)
    # Instanciamos wx.PrintPreview.
    preview = wx.PrintPreview(printout1, printout2, data)
    if not preview.Ok():
        wx.MessageBox(t(u"No se puede mostrar la vista preliminar", idioma), t(u"Atención", idioma),
                      wx.OK)
        return
    pfrm = wx.PreviewFrame(preview, frame, t(u"Vista preliminar de impresión", idioma))
    pfrm.Initialize()
    pfrm.SetPosition(frame.GetPosition())
    pfrm.SetSize(frame.GetSize())
    pfrm.Show(True)
    
def f_imprimir_ogl(ogl, frame, print_data, idioma = None):
    '''Función para imprimir diseño del OGL'''
    data = wx.PrintDialogData(print_data)
    printout = MyPrintout(ogl.canvas)
    printout2 = MyPrintout(ogl.canvas)
    preview = wx.PrintPreview(printout, printout2, data)
    if not preview.Ok(): return
    pfrm = wx.PreviewFrame(preview, frame, t(u"Vista preliminar de impresión", idioma))
    pfrm.Initialize()
    pfrm.SetPosition(frame.GetPosition())
    pfrm.SetSize(frame.GetSize())
    pfrm.Show(True)

def f_configurar_impresion(print_data, frame):
    '''Función de configuración de impresión'''
    psdd = wx.PageSetupDialogData(print_data)
    psdd.CalculatePaperSizeFromId()
    dlg = wx.PageSetupDialog(frame, psdd)
    dlg.ShowModal()
    aux = wx.PrintData(dlg.GetPageSetupData().GetPrintData())
    dlg.Destroy()
    return aux 
